package org.lazycoder.database;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;

/**
 * Dynamically sized table implemented with ArrayLists forming a 2d array. This
 * is intended for use with Database class to retrieve data.
 * 
 * @author Matthew Bayliss
 * 
 */
public class Table {
	/** Friendly names for columns */
	protected HashMap<String, String> fNames;
	private ResultSet rs;
	private ResultSetMetaData md;
	private PreparedStatement ps;

	public Table(PreparedStatement sql) {
		try {
			fNames = new HashMap<String, String>();
			ps = sql;
			rs = ps.executeQuery();
			md = rs.getMetaData();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void setFriendlyName(int column, String name) {
		String cName;
		try {
			cName = md.getColumnName(column);

			fNames.put(cName, name);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public boolean hasFriendlyName(int column) {
		String cName;
		try {
			cName = md.getColumnName(column);

			if (fNames.containsKey(cName)) {
				return true;
			} else {
				return false;
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}

	public String getFriendlyName(int column) {
		String cName;
		try {
			cName = md.getColumnName(column);

			if (fNames.containsKey(cName)) {
				return fNames.get(cName);
			} else {
				return cName;
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * @return The number of cols in the table.
	 */
	public int getCols() {
		try {
			rs.first();
			return md.getColumnCount();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * Grab an element from the table. This is important for AbstractTableModels
	 * which rely on having random access.
	 * 
	 * @param x
	 *            x coordinate
	 * @param y
	 *            y coordinate
	 * @return the value at (x,y)
	 */
	public String getElement(int x, int y) {
		try {
			rs.absolute(x + 1);
			String out = rs.getString(y + 1);
			return out;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Get the header row
	 * 
	 * @return all the headers
	 */
	public String getHeader(int x) {
		try {
			return md.getColumnName(x);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Get an iterator to walk through the entire table by row. You can then
	 * grab another iterator from the ArrayList returned to gather data.
	 * loop-the-loopy loop.
	 * 
	 * @return an iterator for the table
	 */
	public Iterator<Vector<String>> getRowIterator() {
		Vector<Vector<String>> result = new Vector<Vector<String>>();
		try {
			rs.first();

			while (rs.next()) {
				Vector<String> row = new Vector<String>();
				for (int j = 1; j <= md.getColumnCount(); j++) {
					row.add(rs.getString(j));
				}
				result.add(row);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result.iterator();
	}

	/**
	 * @return The number of rows in the table.
	 */
	public int getRows() {
		try {
			rs.last();
			return rs.getRow();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * This isn't strictly nessecary but I find that it's a useful debug tool to
	 * create a toString that provides useful data.
	 * 
	 * @return the table formatted as a string.
	 */
	@Override
	public String toString() {
		String output = "";
		try {
			rs.beforeFirst();
			while (rs.next()) {
				for (int i = 1; i <= md.getColumnCount(); i++) {
					output = output.concat(rs.getString(i)) + "\t";
				}
				output = output.concat("\n");
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return output;
	}

	public void update() {
		try {
			rs = ps.executeQuery();
			md = rs.getMetaData();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
